function FacetEngine() {
  this._facets = [];
  this._views = [];
}

FacetEngine.prototype.addFacet = function(facet) {
  this._facets.push(facet);
};

FacetEngine.prototype.addView = function(view) {
  this._views.push(view);
};

FacetEngine.prototype.getBaseCollection = function() {
  return {};
};

FacetEngine.prototype.getFilteredCollection = function(except) {
  var c = this.getBaseCollection();
  $.each(this._facets, function(i, facet) {
    if (facet !== except) {
      c = facet.restrict(c);
    }
  });
  return c;
};

FacetEngine.prototype.update = function(except) {
  var self = this;
  $.each(this._facets, function(i, facet) {
    if (facet !== except) {
      facet.update(self.getFilteredCollection(facet));
    }
  });
  
  var c = this.getFilteredCollection();
  $.each(this._views, function(i, view) {
    view.update(c);
  });
};

function Facet(engine, elmt) {
  this._engine = engine;
  this._elmt = elmt;
}

Facet.prototype.initialize = function(title) {
  this._elmt.html(DOM.loadHTML('scripts/common/facet.html'));
  this._elmts = DOM.bind(this._elmt);
  this._elmts.headerLabel.text(title);
  
  this._selection = [];
};

Facet.prototype.restrict = function(c) {
  throw new Error('Not implemented');
};

Facet.prototype.update = function(c) {
  throw new Error('Not implemented');
};


Facet.prototype._renderChoices = function(items) {
  var self = this;
  var choiceList = this._recomputeChoiceList(items);
  var facetBody = this._elmts.facetBody.empty().removeClass('progressing');
  var selectedCount = this._selection.length;
  
  /*
  if (selectedCount > 0) {
    this._elmts.resetLink.show();
  } else {
    this._elmts.resetLink.hide();
  }
  */
  $.each(
    choiceList,
    function(i, choice) {
      var div = $('<div>').addClass('facet-choice').appendTo(facetBody);
      if (choice.selected) {
        div.addClass('selected');
        if (selectedCount > 1) {
          $('<a>')
            .addClass('facet-choice-control')
            .attr('href', 'javascript:{}')
            .text('exclude')
            .appendTo(div)
            .click(function() {
              self._onChoice(choice, false);
            });
        }
      } else {
        if (selectedCount > 0) {
          $('<a>')
            .addClass('facet-choice-control')
            .attr('href', 'javascript:{}')
            .text('include')
            .appendTo(div)
            .click(function() {
              self._onChoice(choice, true, false);
            });
        }
      }
      
      $('<span>')
        .addClass('facet-choice-count')
        .text(formatInteger(choice.count))
        .appendTo(div);
        
      var a = $('<a>')
        .addClass('facet-choice-label')
        .attr('href', 'javascript:{}')
        .text(choice.label)
        .appendTo(div);
      if (choice.selected && selectedCount == 1) {
        a.click(function() {
          self._onChoice(choice, false);
          div.removeClass('selected');
        });
      } else {
        a.click(function() {
          self._onChoice(choice, true, true);
          div.addClass('selected');
        });
      }
      
      if (choice.description) {
        $('<div>')
          .addClass('facet-choice-description')
          .text(choice.description)
          .appendTo(div);
      }
    }
  );
};

Facet.prototype._buildSelectionMap = function() {
  var selectionMap = {};
  $.each(this._selection, function(i, item) {
    selectionMap[item.value] = item;
  });
  return selectionMap;
};

Facet.prototype._recomputeChoiceList = function(items) {
  var selectionMap = this._buildSelectionMap();
  var choiceList = [];
  $.each(items, function(i, item) {
    choiceList.push(item);
    if (item.value in selectionMap) {
      item.selected = true;
      delete selectionMap[item.value]
    } else {
      item.selected = false;
    }
  });
  $.each(selectionMap, function(value, item) {
    item.count = 0;
    choiceList.push(item);
  });
  
  this._sortChoices(choiceList);
  
  return choiceList;
};

Facet.prototype._sortChoices = function(choiceList) {
  choiceList.sort(function(a, b) { return a.label.localeCompare(b.label); });
};

Facet.prototype._onChoice = function(item, select, only) {
  var self = this;
  var buildSelectionExcept = function(except) {
    var newSelection = [];
    $.each(self._selection, function(i, item2) {
      if (!(except) || item2.value != except.value) {
        newSelection.push(item2);
      }
    });
    return newSelection;
  };
  
  if (select) {
    if (only) {
      this._makeSelection([ item ]);
    } else {
      var selection = buildSelectionExcept(item);
      selection.push(item);
      this._makeSelection(selection);
    }
  } else {
    this._makeSelection(buildSelectionExcept(item));
  }
};

Facet.prototype._makeSelection = function(selection) {
  this._selection = selection;
  this._engine.update();
};
